package com.quwan.common.exception;

import com.quwan.common.result.ApiResult;
import com.quwan.common.result.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 处理 SpringMVC 请求参数缺失
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public ApiResult<String> missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException ex) {
        log.warn("[missingServletRequestParameterExceptionHandler]", ex);
        return ApiResult.error(ResultCode.PARAM_MISS);
    }

    /**
     * 处理 SpringMVC 请求参数缺失
     */
    @ExceptionHandler(value = UsernameNotFoundException.class)
    public ApiResult<String> usernameNotFoundExceptionHandler(UsernameNotFoundException ex) {
        log.info("[usernameNotFoundExceptionHandlerExceptionHandler]", ex);
        return ApiResult.error(400,ex.getMessage());
    }

    /**
     * 处理 SpringMVC 请求参数类型错误
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ApiResult<String> methodArgumentTypeMismatchExceptionHandler(MethodArgumentTypeMismatchException ex) {
        log.warn("[missingServletRequestParameterExceptionHandler]", ex);
        return ApiResult.error(ResultCode.PARAM_TYPE_ERROR);
    }

    /**
     * 处理 SpringMVC 参数校验不正确
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResult<String> methodArgumentNotValidExceptionExceptionHandler(MethodArgumentNotValidException ex) {
        log.warn("[methodArgumentNotValidExceptionExceptionHandler]", ex);
        FieldError fieldError = ex.getBindingResult().getFieldError();
        return ApiResult.error(400, "请求参数不正确" + (fieldError == null ? "" : "：" + fieldError.getDefaultMessage()));
    }

    /**
     * 处理 SpringMVC 参数绑定不正确
     */
    @ExceptionHandler(BindException.class)
    public ApiResult<String> bindExceptionHandler(BindException ex) {
        log.warn("[handleBindException]", ex.getMessage());
        FieldError fieldError = ex.getFieldError();
        return ApiResult.error(400, "请求参数不正确" + (fieldError == null ? "" : "：" + fieldError.getDefaultMessage()));
    }

    /**
     * 处理 Validator 校验不通过产生的异常
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    public ApiResult<String> constraintViolationExceptionHandler(ConstraintViolationException ex) {
        log.warn("[constraintViolationExceptionHandler]", ex);
        ConstraintViolation<?> constraintViolation = ex.getConstraintViolations().iterator().next();
        return ApiResult.error(400, "请求参数不正确：" + constraintViolation.getMessage());
    }

    /**
     * 请求方法不正确
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ApiResult<String> httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException ex,HttpServletRequest request) {

        log.warn("[httpRequestMethodNotSupportedExceptionHandler]:[{}] {} {} ",request.getRequestURL().toString(),ex.getMethod()," method not Supported");
        return ApiResult.error(400, "请求方法不支持：" + ex.getMethod());
    }

    /**
     * 处理业务异常 ServiceException
     */
    @ExceptionHandler(value = ServiceException.class)
    public ApiResult<String> serviceExceptionHandler(ServiceException ex) {
        log.warn("[serviceExceptionHandler]", ex);
        return ApiResult.error(500, ex.getMessage());
    }


    /**
     * 登录异常  返回为自定义异常信息
     */
    @ExceptionHandler(value = LoginException.class)
    public ApiResult<String> loginExceptionHandler(LoginException ex) {
        log.info("[loginExceptionHandler]", ex);
        return ApiResult.error(ex.getCode(), ex.getMessage());
    }
    /**
     * 支付  返回为自定义异常信息
     */
    @ExceptionHandler(value = PayException.class)
    public ApiResult<String> payExceptionHandler(PayException ex) {
        log.info("[payExceptionHandler]{}", ex);
        return ApiResult.error(ex.getCode(), ex.getMessage());
    }
    /**
     * 统一异常返回消息提示  自定义异常信息
     * 优化性能 不调用本地方法 无法打印方法栈异常日志
     */
    @ExceptionHandler(value = ResponseException.class)
    public ApiResult<String> ResponseExceptionHandler(ResponseException ex) {
        log.info("[responseExceptionHandler]\n{}",   ex.toString());
        return ApiResult.error(ex.getCode(), ex.getMessage());
    }

    /**
     * 处理系统异常，兜底处理所有的一切
     */
    @ExceptionHandler(value = Exception.class)
    public ApiResult<String> defaultExceptionHandler(HttpServletRequest req, Throwable ex) {
        log.error("[defaultExceptionHandler]", ex);
        return ApiResult.error(ResultCode.INTERNAL_SERVER_ERROR);
    }

}
